package gormmysql

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"sync"

	Log "github.com/cihub/seelog"
	"gopkg.in/ini.v1"

	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

var (
	dbs                 = map[string]*gorm.DB{} //主数据库操作对象
	createDefaultDbOnce sync.Once               //单次赋值操作
)

// 初始化
func init() {

}

// 数据源信息
type DataSourceInfo struct {
	Name        string `json:"name"`
	User        string `json:"user"`
	Pass        string `json:"pass"`
	Ip          string `json:"ip"`
	Port        string `json:"port"`
	DbName      string `json:"dbName"`
	PrintSql    bool   `json:"printSql"`
	AutoMigrate bool   `json:"autoMigrate"` //是否开启AutoMigrate功能(会创建表、缺失的外键、约束、列和索引)
	PassKey     string `json:"passKey"`     //加密密钥
}

/**
 * 创建默认数据库连接
 * @param dataSourceName 数据源名称
 * @param configFilePath 配置文件路径
 * @return
 */
func NewDbByDefaultDb(dataSourceName string) (bool, string, interface{}) {
	root := ""
	exePath, err := os.Executable()
	if err != nil {
		root = "."
	}

	root, _ = filepath.EvalSymlinks(filepath.Dir(exePath))

	configFilePath := filepath.Join(root, "config", "app.ini")

	if dataSourceName == "" {
		dataSourceName = "default"

	}

	return NewDbByIni(dataSourceName, configFilePath)
}

/**
 * 通过配置文件创建数据库连接
 */
func NewDbByIni(dataSourceName string, configFilePath string) (bool, string, interface{}) {
	if _, err := os.Stat(configFilePath); os.IsNotExist(err) {
		Log.Error("配置文件不存在:", configFilePath)
		return false, "配置文件不存在", 1011
	}

	cfg, err := ini.Load(configFilePath)
	if err != nil {
		Log.Error("配置文件读取错误:", err)
		return false, "配置文件读取错误", 1012
	}

	if !cfg.HasSection("DataSource") {
		Log.Debug("配置文件没有DataSource,不进行数据库连接")
		return false, "配置文件没有DataSource,不进行数据库连接", 1013
	}

	DataSource := cfg.Section("DataSource")

	dataSourceInfo := DataSourceInfo{
		Name:        "default",
		User:        "root",
		Pass:        "view",
		Ip:          "127.0.0.1",
		Port:        "3306",
		DbName:      "mysql",
		PrintSql:    false,
		AutoMigrate: false,
	}

	if value, err := DataSource.GetKey("User"); err == nil {
		dataSourceInfo.User = value.String()
	}

	if value, err := DataSource.GetKey("Pass"); err == nil {
		dataSourceInfo.Pass = value.String()
	}

	if value, err := DataSource.GetKey("Ip"); err == nil {
		dataSourceInfo.Ip = value.String()
	}

	if value, err := DataSource.GetKey("Port"); err == nil {
		dataSourceInfo.Port = value.String()
	}

	if value, err := DataSource.GetKey("MainDb"); err == nil {
		dataSourceInfo.DbName = value.String()
	}

	if value, err := DataSource.GetKey("PrintSql"); err == nil {
		tmp, _ := value.Int()
		dataSourceInfo.PrintSql = tmp == 1
	}

	if value, err := DataSource.GetKey("AutoMigrate"); err == nil {
		tmp, _ := value.Int()
		dataSourceInfo.AutoMigrate = tmp == 1
	}

	return NewDb(dataSourceInfo)
}

/**
 * 创建数据库连接
 */
func NewDb(dataSourceInfo DataSourceInfo) (bool, string, interface{}) {
	dbConfig := &gorm.Config{
		DisableForeignKeyConstraintWhenMigrating: !dataSourceInfo.AutoMigrate,
	}

	if dataSourceInfo.PrintSql {
		dbConfig.Logger = logger.Default.LogMode(logger.Info) //开启sql打印
	}

	pass := dataSourceInfo.Pass
	if len(pass) > 3 && strings.HasPrefix(pass, "${") && strings.HasSuffix(pass, "}") {
		passKey := dataSourceInfo.PassKey
		if len(passKey) == 0 {
			passKey = "bricks"
		}

		dataSourceInfo.Pass = AesUtil{}.Decrypt(pass[2:len(pass)-1], passKey)
	}

	//dsn := "root:view@tcp(127.0.0.1:3306)/Dev_BricksBaseSystem?charset=utf8mb4&parseTime=True&loc=Local"
	//dsn := user + ":" + pass + "@tcp(" + ip + ":" + port + ")/" + dbName + "?charset=utf8mb4&serverTimezone=GMT%2B8&parseTime=True&loc=Local"
	dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", dataSourceInfo.User, dataSourceInfo.Pass, dataSourceInfo.Ip, dataSourceInfo.Port, dataSourceInfo.DbName)

	db, err := gorm.Open(mysql.Open(dsn), dbConfig)
	if err != nil {
		Log.Error("连接数据库错误:", err)
		return false, err.Error(), 1001
	}

	return true, "连接数据库成功", db
}

// 添加gorm操作对象
func AddDB(dataSourceInfo DataSourceInfo) *gorm.DB {
	bl, _, data := NewDb(dataSourceInfo)
	if !bl {
		return nil
	}

	result := data.(*gorm.DB)

	name := dataSourceInfo.Name
	if name == "" {
		name = "default"
	}

	dbs[name] = result

	return result
}

// 取gorm操作对象
func GetDB(names ...string) *gorm.DB {
	if len(names) == 0 {
		names = []string{"default"}
	}

	name := names[0]
	if result, ok := dbs[name]; ok {
		return result
	}

	if name != "default" {
		return nil
	}

	createDefaultDbOnce.Do(func() {
		bl, _, data := NewDbByDefaultDb(name)
		if !bl {
			Log.Error("默认数据库连接失败,关闭程序")
			os.Exit(1)
			return
		}

		dbs[name] = data.(*gorm.DB)
	})

	return dbs[name]
}
